package org.springblade.modules.admin.service.impl;

import cn.hutool.json.JSONUtil;
import com.aliyun.dyvmsapi20170525.models.IvrCallRequest;
import com.aliyun.dyvmsapi20170525.models.IvrCallResponse;
import com.aliyun.oss.ServiceException;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springblade.common.constant.BaseRoleConstant;
import org.springblade.common.constant.IvrVoiceConstant;
import org.springblade.common.utils.ivrcall.IvrCallUtil;
import org.springblade.core.mp.base.BaseEntity;
import org.springblade.core.mp.base.BaseServiceImpl;
import org.springblade.core.tenant.annotation.TenantIgnore;
import org.springblade.core.tenant.mp.TenantEntity;
import org.springblade.core.tool.utils.Func;
import org.springblade.modules.admin.dto.ChatGroupDTO;
import org.springblade.modules.admin.dto.RobotPushDTO;
import org.springblade.modules.admin.entity.*;
import org.springblade.modules.admin.enums.ChatGroupRobotEnum;
import org.springblade.modules.admin.enums.GroupRobotEnum;
import org.springblade.modules.admin.enums.MaintainPlanContentEnum;
import org.springblade.modules.admin.mapper.ChatGroupMapper;
import org.springblade.modules.admin.service.*;
import org.springblade.modules.admin.vo.RobotBuildingElevatorPushVO;
import org.springblade.modules.admin.vo.RobotGroupVO;
import org.springblade.modules.system.service.IRoleService;
import org.springblade.modules.system.service.IUserService;
import org.springblade.modules.system.vo.SimpleUserVO;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;


/**
 * Robot chat group service impl
 *
 * @author Sharry
 * @since 2023/5/15
 */
@Service
@Slf4j
@AllArgsConstructor
public class ChatGroupServiceImpl extends BaseServiceImpl<ChatGroupMapper, ChatGroup> implements IChatGroupService {

	private final IRobotService robotService;

	private final IChatGroupBuildingService cgbSerivce;

	private final IRobotBuildingElevatorService rbeService;

	private final GroupRobotConfigService groupRobotConfigService;

	private final IRoleService roleService;

	private final IUserService userService;

	private final IvrCallUtil ivrCallUtil;


	/**
	 * 新增单条群-机器人绑定信息
	 *
	 * @param chatGroupDTO 绑定信息参数
	 * @return 是否成功
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public Boolean addOne(ChatGroupDTO chatGroupDTO) {
		ChatGroup chatGroup = new ChatGroup();
		chatGroup.setGroupId(chatGroupDTO.getRoomId());
		chatGroup.setRobotId(chatGroupDTO.getRobotId());
		chatGroup.setName(chatGroupDTO.getRoomName());
		return save(chatGroup);
	}

	@Override
	@TenantIgnore
	@Transactional(rollbackFor = Exception.class)
	public Boolean updateGroupNameTopic(ChatGroupDTO chatGroupDTO) {
		// 1. 根据 唯一的群id 获取群对象
		String roomId = chatGroupDTO.getRoomId();
		ChatGroup thisOne = getOne(new LambdaQueryWrapper<ChatGroup>().eq(ChatGroup::getGroupId, roomId));
		if (Func.isNull(thisOne)) {
			throw new ServiceException("失败，该群不存在！");
		}
		// 2. 执行更新:更改群名
		thisOne.setName(chatGroupDTO.getRoomName());
		return updateById(thisOne);
	}

	@Override
	@TenantIgnore
	public Boolean roomJoin(ChatGroupDTO chatGroupDTO) {
		// 0. 先根据参数获取机器人本身的信息
		String robotId = chatGroupDTO.getRobotId();
		Robot robot = robotService.getOne(new LambdaQueryWrapper<Robot>().eq(Robot::getRobotId, robotId));
		if (Func.isNull(robot)) {
			throw new ServiceException("业务异常：该微信号对应的机器人未添加或不存在，请联系管理员");
		}
		String tenantId = robot.getTenantId();
		if (Func.isNull(tenantId)) {
			throw new ServiceException("业务异常：该机器人信息异常，请联系管理员");
		}

		// 1. 判断是否已入群
		// 根据 唯一的群id 获取群对象
		String roomId = chatGroupDTO.getRoomId();
		ChatGroup thisOne = getOne(new LambdaQueryWrapper<ChatGroup>().eq(ChatGroup::getGroupId, roomId));

		// 2. 是：若是异常状态，更新状态
		if (!Func.isNull(thisOne)) {
			thisOne.setStatus(ChatGroupRobotEnum.ROBOT_STATUS_NORMALLY.getKey());
			thisOne.setTenantId(tenantId);
			return updateById(thisOne);
		}
		// 3. 否：执行新增
		ChatGroup chatGroup = new ChatGroup();
		chatGroup.setGroupId(chatGroupDTO.getRoomId());
		chatGroup.setRobotId(robotId);
		chatGroup.setName(chatGroupDTO.getRoomName());
		chatGroup.setTenantId(tenantId);
		return save(chatGroup);
	}

	@Override
	@TenantIgnore
	public Boolean roomLeave(ChatGroupDTO chatGroupDTO) {
		String roomId = chatGroupDTO.getRoomId();
		ChatGroup thisOne = getOne(new LambdaQueryWrapper<ChatGroup>().eq(ChatGroup::getGroupId, roomId));
		// 当要退出的群不存在时，抛异常
		if (Func.isNull(thisOne)) {
			throw new ServiceException("退群失败！请先加群！");
		}
		thisOne.setStatus(ChatGroupRobotEnum.ROBOT_STATUS_EXCEPTION.getKey());
		return updateById(thisOne);
	}

	@Override
	@TenantIgnore
	public Boolean heartbeat(ChatGroupDTO chatGroupDTO) {
		// 1. 获取 robotId 心跳数据状态
		String robotId = chatGroupDTO.getRobotId();
		Integer robotStatus = chatGroupDTO.getRobotStatus();
		if (Func.isNull(robotId)) {
			throw new ServiceException("业务异常，robotId获取失败！");
		}
		if (Func.isNull(robotStatus)) {
			throw new ServiceException("业务异常，机器人状态获取失败！");
		}
		// 2. 获取 robotId 对应的robot
		Robot thisRobot = robotService.getOne(new LambdaQueryWrapper<Robot>().eq(Robot::getRobotId, robotId));
		if (Func.isNull(thisRobot)) {
			throw new ServiceException("业务异常，该机器人不存在，请先联系管理员添加机器人");
		}
		// 3. 执行心跳包的更新操作
		thisRobot.setStatus(robotStatus);
		return robotService.updateById(thisRobot);
	}

	@Override
	public IPage<RobotGroupVO> relationList(RobotPushDTO robotPushDTO, IPage<RobotGroupVO> page, String tenantId) {
		String groupName = robotPushDTO.getGroupName();
		String groupId = robotPushDTO.getGroupId();
		List<Long> buildingIds = robotPushDTO.getBuildingIds();
		List<Long> elevatorIds = robotPushDTO.getElevatorIds();
		Integer status = robotPushDTO.getStatus();
		String robotId = robotPushDTO.getRobotId();
		IPage<RobotGroupVO> result = baseMapper.relationList(groupName,
			page, groupId, buildingIds, elevatorIds, status, robotId, tenantId
		);
		if (Func.isEmpty(result)) {
			return result;
		}
		// 2023-10-10 新增配置列表
		List<RobotGroupVO> forConfig = result.getRecords();
		for (RobotGroupVO r : forConfig) {
			Long id = r.getId();
			List<GroupRobotConfig> listForHover = groupRobotConfigService.list(
				new LambdaQueryWrapper<GroupRobotConfig>()
					.eq(GroupRobotConfig::getChatgroupId, id)
					.eq(TenantEntity::getTenantId, tenantId)
					.eq(BaseEntity::getIsDeleted, 0)
			);
			if (Func.isNotEmpty(listForHover)) {
				// 新增返回树形结构
				List<Integer> maintain = new ArrayList<>(4);
				List<Integer> repair = new ArrayList<>(5);
				List<Integer> rescue = new ArrayList<>(4);
				Map<Integer, List<Integer>> configMap = new HashMap<>(3);
				listForHover.forEach(l -> {
					// 根据枚举类获取对应类型，并设置进入冗余字段
					if (l.getStatus().equals(MaintainPlanContentEnum.MAINTAIN_BY.getId())) {
						maintain.add(l.getPushType());
					} else if (l.getStatus().equals(MaintainPlanContentEnum.MAINTAIN_WX.getId())) {
						repair.add(l.getPushType());
					} else if(l.getStatus().equals(MaintainPlanContentEnum.MAINTAIN_KR.getId())){
						rescue.add(l.getPushType());
					}
				});
				configMap.put(GroupRobotEnum.MAINTAIN_BEGIN.getStatus(), maintain);
				configMap.put(GroupRobotEnum.REPAIR_SEND.getStatus(), repair);
				configMap.put(MaintainPlanContentEnum.MAINTAIN_KR.getId(), rescue);
				r.setConfigMap(configMap);
			}
		}
		// 查全部数据，统计结果赋值:
		List<RobotGroupVO> records = result.getRecords();
		for (RobotGroupVO record : records) {
			Long id = record.getId();
			int count = cgbSerivce.count(new LambdaQueryWrapper<ChatGroupBuilding>()
				.eq(ChatGroupBuilding::getChatgroupId, id)
				.eq(ChatGroupBuilding::getTenantId, tenantId)
				.eq(BaseEntity::getIsDeleted, 0)
			);
			record.setProjectNum(count);

			int count1 = (int) rbeService.list(new LambdaQueryWrapper<RobotBuildingElevator>()
				.eq(RobotBuildingElevator::getChatgroupId, id)
				.eq(RobotBuildingElevator::getTenantId, tenantId)
				.eq(BaseEntity::getIsDeleted, 0)
			).stream().filter(distinctByKey(RobotBuildingElevator::getElevatorId)).count();

			record.setElevatorNum(count1);
		}
		result.setRecords(records);
		return result;
	}

	@Override
	public List<RobotBuildingElevatorPushVO> getBeVoList(String groupId, RobotPushDTO robotPushDTO) {
		return baseMapper.getBeVoList(groupId, robotPushDTO);
	}

	/**
	 * 去重方法
	 *
	 * @param keyExtractor 去重依据
	 * @param <T>          占位符
	 */
	public <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
		Map<Object, Boolean> seen = new ConcurrentHashMap<>();
		return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
	}

	@Override
	public String getServiceTelephone(String groupId) {
		String tenantId = null;
		String buildingName = null;
		if (Func.isNotBlank(groupId)) {
			ChatGroup chatGroup = this.getOne(Wrappers.<ChatGroup>lambdaQuery().eq(ChatGroup::getGroupId, groupId), false);
			if (chatGroup != null && chatGroup.getStatus() == ChatGroupRobotEnum.ROBOT_STATUS_NORMALLY.getKey() && chatGroup.getPushAllow() == ChatGroupRobotEnum.GROUP_PUSH_OPEN.getKey()) {
				tenantId = chatGroup.getTenantId();
			}
			ChatGroupBuilding chatGroupBuilding = cgbSerivce.getOne(Wrappers.<ChatGroupBuilding>lambdaQuery().eq(ChatGroupBuilding::getChatgroupId, chatGroup.getId()), false);
			if (chatGroupBuilding != null) {
				buildingName = chatGroupBuilding.getName();
			}
		}

		// 暂时写死获取客服角色电话
		String phones = "";
		Long roleId = roleService.getRoleIdByAliases(tenantId, BaseRoleConstant.WAITER);
		if (roleId != null) {
			List<SimpleUserVO> simpleUsers = userService.getUserByDeptAndRole(null, roleId);
			if (simpleUsers != null) {
				phones =  simpleUsers.stream().map(SimpleUserVO::getPhone).collect(Collectors.joining(","));
			}
		}

		// 发送语音通知
		if (Func.isNoneBlank(phones, buildingName)) {
			List<String> noticePhones = Func.toStrList(phones);
			Map<String, String> params = new HashMap<>(2);
			params.put("location", buildingName);
			params.put("channel", "微信群");
			for (String noticePhone : noticePhones) {
				IvrCallUtil.IvrCallRequestDto ivrCallRequestDto = new IvrCallUtil.IvrCallRequestDto();
				ivrCallRequestDto.setCalledNumber(noticePhone);
				ivrCallRequestDto.setStartCode(IvrVoiceConstant.TTS_2);
				ivrCallRequestDto.setStartTtsParams(params);
				ivrCallRequestDto.setOutId(groupId);
				List<IvrCallRequest.IvrCallRequestMenuKeyMap> list = new ArrayList<>();
				IvrCallRequest.IvrCallRequestMenuKeyMap keyMap1 = new IvrCallRequest.IvrCallRequestMenuKeyMap();
				keyMap1.setKey("1");
				keyMap1.setCode("c68859f5-bf6d-474d-a3c4-d3271ea35c54.wav");// 设置第一个对象的属性
				list.add(keyMap1);
				ivrCallRequestDto.setMenuKeyMap(list);
				try {
					IvrCallResponse response = ivrCallUtil.initiateIvrCall(ivrCallRequestDto);
					log.info("AI客服ivr,phone:[{}], 请求呼叫结果， Body: {}", noticePhone, JSONUtil.toJsonStr(response));
				} catch (Exception e) {
					log.error("AI客服ivr，phone:[{}], 呼叫失败: [{}]", noticePhone, e.getMessage());
				}
			}
		}

		return phones;
	}
}
